Projekt Automatyczna Analiza Obrazu

Author

Michał Koziński i Patryk Marek

Tematyka zadania

Celem tego projektu jest zbudowanie modelu konwolucyjnej sieci neuronowej służącej do klasyfikacji dzieł sztuki ze względu na gatunek (11 etykiet) oraz stylów malarskich (27 etykiet).

Zbiór danych którego użylismy do trenowania modeli jest WikiArt, zawiera on ponad 84 tysiące różnych obrazów. Zbiór ten funkcjonuje w otwartym dostępie i jest darmowy do niekomercyjnego użytku.

Największą trudność zadania stanowi fakt, że klasyfikacja obrazów jest zadaniem o charakterze abstrakcyjnym w zestawieniu z klasyfikacją przedmitów, ludzi lub zwirząt.

Dodatkowo specyfika zadania uniemożliwa wykorzystanie augmentacji, wynika to z tego, że dla danego obrazu możliwy jest tylko oryginalny sposób reprezentacji, zgodny z projektem artysty.

Klasyfikacja gatunku obrazu

Każdy z obrazów posiada etykietę wskazującą na gatunek obrazu:

  • 0 - Malarstwo abstrakcyjne;

  • 1 - Pejzaż miejski;

  • 2 - Malarstwo rodzajowe;

  • 3 - Ilustracja;

  • 4 - Pejzaż;

  • 5 - Malarstwo nagie;

  • 6 - Portret;

  • 7 - Malarstwo religijne;

  • 8 - Szkic;

  • 9 - Martwa natura;

  • 10 - Gatunek nieznany.

Pierwszy projekt sieci

Pierwsza testowana przez nas architekutra sieci jest stosunkowo prosta, ponieważ składa się jedynie z 4 warstw konwolucyjnych i łączących (w tym wypadku - “max poolingowych”) ze stosunkowo niewielką ilością filtrów.

Kod
model <- keras_model_sequential() %>%
  layer_conv_2d(filters = 32, kernel_size = c(3, 3), activation = "relu",
                input_shape = c(150, 150, 3)) %>%
  layer_max_pooling_2d(pool_size = c(2, 2)) %>%
  layer_conv_2d(filters = 64, kernel_size = c(3, 3), activation = "relu") %>%
  layer_max_pooling_2d(pool_size = c(2, 2)) %>%
  layer_conv_2d(filters = 128, kernel_size = c(3, 3), activation = "relu") %>%
  layer_max_pooling_2d(pool_size = c(2, 2)) %>%
  layer_conv_2d(filters = 128, kernel_size = c(3, 3), activation = "relu") %>%
  layer_max_pooling_2d(pool_size = c(2, 2)) %>%
  layer_flatten() %>%
  layer_dense(units = 512, activation = "relu") %>%
  layer_dense(units = 11, activation = "softmax")
Model: "sequential"
________________________________________________________________________________
Layer (type)                        Output Shape                    Param #     
================================================================================
conv2d_3 (Conv2D)                   (None, 148, 148, 32)            896         
________________________________________________________________________________
max_pooling2d_3 (MaxPooling2D)      (None, 74, 74, 32)              0           
________________________________________________________________________________
conv2d_2 (Conv2D)                   (None, 72, 72, 64)              18496       
________________________________________________________________________________
max_pooling2d_2 (MaxPooling2D)      (None, 36, 36, 64)              0           
________________________________________________________________________________
conv2d_1 (Conv2D)                   (None, 34, 34, 128)             73856       
________________________________________________________________________________
max_pooling2d_1 (MaxPooling2D)      (None, 17, 17, 128)             0           
________________________________________________________________________________
conv2d (Conv2D)                     (None, 15, 15, 128)             147584      
________________________________________________________________________________
max_pooling2d (MaxPooling2D)        (None, 7, 7, 128)               0           
________________________________________________________________________________
flatten (Flatten)                   (None, 6272)                    0           
________________________________________________________________________________
dense_1 (Dense)                     (None, 512)                     3211776     
________________________________________________________________________________
dense (Dense)                       (None, 11)                      5643        
================================================================================
Total params: 3,458,251
Trainable params: 3,458,251
Non-trainable params: 0
________________________________________________________________________________

Szkolenie w każdej epoce odbywało się na 3200 obrazkach, a walidacja była przeprowadzana na 1600 obrazkach.

Funkcją optymalizującą był “Adam” oraz zastosowane zostały następujące callbacki:

  • Zapisywanie modelu po każdej epoce;

  • Przerwanie procesu uczenia, jeżeli celność nie poprawi się na zbiorze walidacyjnym po 5 epokach.

Przy tej strukturze sieć szkoliła się przez 28 epok, kończąc proces uczenia przez zastosowanie callbacków ze względu na brak poprawy celności na zbiorze walidacyjnym.

Pierwsza sieć

Widać że nastąpiło zjawisko przeuczenia. Najwyższą celnością na zbiorze walidacyjnym było ~45%.

Drugi projekt sieci

Druga architektura składa się z większej liczby warstw konwolucyjnych oraz większej ilości filtrów. Dodatkowo tym razem dodaliśmy warstwy dropout’ów w celu redukcji przeuczenia sieci.

Kod
model <- keras_model_sequential() %>%
  layer_conv_2d(filters = 128, kernel_size = c(3, 3), activation = "relu",
                input_shape = c(150, 150, 3)) %>%
  layer_conv_2d(filters = 128, kernel_size = c(3, 3), activation = "relu") %>%
  layer_max_pooling_2d(pool_size = c(2, 2)) %>%
  layer_dropout(rate = 0.2) %>%
  layer_conv_2d(filters = 64, kernel_size = c(3, 3), activation = "relu") %>%
  layer_conv_2d(filters = 64, kernel_size = c(3, 3), activation = "relu") %>%
  layer_max_pooling_2d(pool_size = c(2, 2)) %>%
  layer_dropout(rate = 0.3) %>%
  layer_conv_2d(filters = 128, kernel_size = c(3, 3), activation = "relu") %>%
  layer_conv_2d(filters = 32, kernel_size = c(3, 3), activation = "relu") %>%
  layer_max_pooling_2d(pool_size = c(2, 2)) %>%
  layer_dropout(rate = 0.3) %>% 
  layer_flatten() %>%
  layer_dense(units = 256, activation = "relu") %>%
  layer_dense(units = 54, activation = "relu") %>%
  layer_dropout(rate = 0.5) %>%
  layer_dense(units = 11, activation = "softmax")
Model: "sequential_1"
________________________________________________________________________________
Layer (type)                        Output Shape                    Param #     
================================================================================
conv2d_9 (Conv2D)                   (None, 148, 148, 128)           3584        
________________________________________________________________________________
conv2d_8 (Conv2D)                   (None, 146, 146, 128)           147584      
________________________________________________________________________________
max_pooling2d_6 (MaxPooling2D)      (None, 73, 73, 128)             0           
________________________________________________________________________________
dropout_3 (Dropout)                 (None, 73, 73, 128)             0           
________________________________________________________________________________
conv2d_7 (Conv2D)                   (None, 71, 71, 64)              73792       
________________________________________________________________________________
conv2d_6 (Conv2D)                   (None, 69, 69, 64)              36928       
________________________________________________________________________________
max_pooling2d_5 (MaxPooling2D)      (None, 34, 34, 64)              0           
________________________________________________________________________________
dropout_2 (Dropout)                 (None, 34, 34, 64)              0           
________________________________________________________________________________
conv2d_5 (Conv2D)                   (None, 32, 32, 128)             73856       
________________________________________________________________________________
conv2d_4 (Conv2D)                   (None, 30, 30, 32)              36896       
________________________________________________________________________________
max_pooling2d_4 (MaxPooling2D)      (None, 15, 15, 32)              0           
________________________________________________________________________________
dropout_1 (Dropout)                 (None, 15, 15, 32)              0           
________________________________________________________________________________
flatten_1 (Flatten)                 (None, 7200)                    0           
________________________________________________________________________________
dense_4 (Dense)                     (None, 256)                     1843456     
________________________________________________________________________________
dense_3 (Dense)                     (None, 54)                      13878       
________________________________________________________________________________
dropout (Dropout)                   (None, 54)                      0           
________________________________________________________________________________
dense_2 (Dense)                     (None, 11)                      605         
================================================================================
Total params: 2,230,579
Trainable params: 2,230,579
Non-trainable params: 0
________________________________________________________________________________

Uczenie tym razem odbywało się na 51200 obrazach w epoce, a następnie model walidowany był na 12800 obrazach.

Funkcją optymalizującą również był “Adam” oraz zastosowane były te same callbacki co przy wcześniejszej architekturze.

Druga sieć

Niestety, także i przy tej architekturze nastąpiło zjawisko przeuczenia (nawet szybciej niż w przypadku sieci poprzedniej) osiągając accuracy maksymalnie na poziomie 0.45.

Trzeci projekt sieci

Tym razem zdecydowaliśmy się użyć wcześniej przeszkolonej sieci ResNet jako części konwolucyjnej. Ze względu na ograniczone zasoby obliczeniowe użyliśmy wersji ResNet50.

ResNet50 to wariant modelu ResNet, który składa się z 48 warstw konwolucyjnych, jednej warstwy łączącej (“Max Pool”) i jednej warstwy łączącej (“Average Pool”). ResNet został zaprojektowany w celu dodawania większej liczby warstw konwolucyjnych do sieci CNN, bez napotkania problemu zanikającego gradientu, za pomocą koncepcji połączeń rezydualnych.

conv_base <- application_resnet50(
  weights = "imagenet",
  include_top = F,
  input_shape = c(224,224,3)
)
freeze_weights(conv_base)
unfreeze_weights(conv_base, from = "conv5_block3_2_conv")

Odmrażamy dwa ostatnie bloki konwolucyjne i normalizujące partię w celu dostrojenia sieci do naszego zadania.

Kod
model <- keras_model_sequential() %>%
  conv_base %>%
  layer_flatten() %>%
  layer_dense(units = 512, activation = "relu") %>%
  layer_dense(units = 11, activation = "softmax")
Model: "sequential_2"
_____________________________________________________________________
Layer (type)                   Output Shape               Param #    
=====================================================================
resnet50 (Functional)          (None, 7, 7, 2048)         23587712   
_____________________________________________________________________
flatten_2 (Flatten)            (None, 100352)             0          
_____________________________________________________________________
dense_6 (Dense)                (None, 512)                51380736   
_____________________________________________________________________
dense_5 (Dense)                (None, 11)                 5643       
=====================================================================
Total params: 74,974,091
Trainable params: 54,801,931
Non-trainable params: 20,172,160
_____________________________________________________________________

Sieć uczona była na pełnym zbiorze treningowym przy użyciu optimizera “Adam” i tych samch callbacków co przy poprzednich architekturach.

Trzecia sieć

W tym przypadku zjawisko przeuczenia nastąpiło nawet szybiciej niż przy poprzednich architekturach.

Czwarty projekt sieci

Kod
model <- keras_model_sequential() %>%
  layer_conv_2d(filters = 128, kernel_size = c(3, 3),
                input_shape = c(224, 224, 3)) %>%
  layer_activation_leaky_relu(alpha = 0.1) %>% 
  layer_max_pooling_2d(pool_size = c(2, 2)) %>%
  layer_conv_2d(filters = 128, kernel_size = c(3, 3)) %>%
  layer_activation_leaky_relu(alpha = 0.1) %>% 
  layer_max_pooling_2d(pool_size = c(2, 2)) %>%
  layer_dropout(rate = 0.2) %>% 
  layer_conv_2d(filters = 64, kernel_size = c(3, 3)) %>%
  layer_activation_leaky_relu(alpha = 0.1) %>% 
  layer_max_pooling_2d(pool_size = c(2, 2)) %>%
  layer_dropout(rate = 0.3) %>% 
  layer_conv_2d(filters = 32, kernel_size = c(3, 3)) %>%
  layer_activation_leaky_relu(alpha = 0.1) %>% 
  layer_max_pooling_2d(pool_size = c(2, 2)) %>%
  layer_flatten() %>%
  layer_dropout(rate = 0.5) %>% 
  layer_dense(units = 512, activation = "relu") %>%
  layer_activity_regularization(l2 = 0.001) %>% 
  layer_dense(units = 11, activation = "softmax")
Model: "sequential_3"
________________________________________________________________________________
Layer (type)                        Output Shape                    Param #     
================================================================================
conv2d_13 (Conv2D)                  (None, 222, 222, 128)           3584        
________________________________________________________________________________
leaky_re_lu_3 (LeakyReLU)           (None, 222, 222, 128)           0           
________________________________________________________________________________
max_pooling2d_10 (MaxPooling2D)     (None, 111, 111, 128)           0           
________________________________________________________________________________
conv2d_12 (Conv2D)                  (None, 109, 109, 128)           147584      
________________________________________________________________________________
leaky_re_lu_2 (LeakyReLU)           (None, 109, 109, 128)           0           
________________________________________________________________________________
max_pooling2d_9 (MaxPooling2D)      (None, 54, 54, 128)             0           
________________________________________________________________________________
dropout_6 (Dropout)                 (None, 54, 54, 128)             0           
________________________________________________________________________________
conv2d_11 (Conv2D)                  (None, 52, 52, 64)              73792       
________________________________________________________________________________
leaky_re_lu_1 (LeakyReLU)           (None, 52, 52, 64)              0           
________________________________________________________________________________
max_pooling2d_8 (MaxPooling2D)      (None, 26, 26, 64)              0           
________________________________________________________________________________
dropout_5 (Dropout)                 (None, 26, 26, 64)              0           
________________________________________________________________________________
conv2d_10 (Conv2D)                  (None, 24, 24, 32)              18464       
________________________________________________________________________________
leaky_re_lu (LeakyReLU)             (None, 24, 24, 32)              0           
________________________________________________________________________________
max_pooling2d_7 (MaxPooling2D)      (None, 12, 12, 32)              0           
________________________________________________________________________________
flatten_3 (Flatten)                 (None, 4608)                    0           
________________________________________________________________________________
dropout_4 (Dropout)                 (None, 4608)                    0           
________________________________________________________________________________
dense_8 (Dense)                     (None, 512)                     2359808     
________________________________________________________________________________
activity_regularization (ActivityRe (None, 512)                     0           
________________________________________________________________________________
dense_7 (Dense)                     (None, 11)                      5643        
================================================================================
Total params: 2,608,875
Trainable params: 2,608,875
Non-trainable params: 0
________________________________________________________________________________

Ze względu na fakt, że pierwsza architektura, pomimo najprostrzej struktury, dawała relatywnie najlepsze wyniki, zdecydowaliśmy się do niej wrócić, jednak tym razem zasotowaliśmy modyfikacje w postaci regurlaryzacji oraz funkcji aktywacji, w postaci “leaky reLU”.

Czwarta sieć

Podczas uczenia callbacki ustawione były na:

  • Zapisywanie modelu po każdej epoce;

  • Przerwanie procesu uczenia, jeżeli funkcja straty nie poprawi się na zbiorze walidacyjnym po 5 epokach;

  • Obniżenie learning rate, jeżeli funkcja straty nie poprawi się na zbiorze walidacyjnym po 3 epokach.

W porównaniu do wszystkich poprzednich struktur ta wypada najlepiej, zarówno na zbiorze uczącym (~67% celności) jak i walidacyjnym (~47% celności).

Niestety, pomimo lepszych wyników uczenia oraz obniżenia learning rate (widać że za pierwszym razem poprawił celność), model jest przeuczony.

Piąty projekt sieci

Pomimo faktu, że modele, które wykorzystywały wcześniej przetrenowaną sieć konwolucyjną ResNet50, okazały się być gorsze nawet od prostych struktur. Zdecydowaliśmy się użyć nowszej struktury DenseNet121, wykorzystującej bardziej zaawansowane połączenia resztowe.

ResNet vs DensNet

Zdecydowaliśmy się na DenseNet121 z tego względu, że jest to najmniejsza struktura z architektur DenseNet, co jest ważne przy ograniczonych zasobach sprzętowych.

Tym razem uznaliśmy jednak, że abstrakcyjny charakter zadania wymaga przeszkolenia całej struktury na nowo, ponieważ wzorce wyuczone na zbiorze “Imagenet” mogą nie dawać zadowalających wyników.

conv_base <- application_densenet121(
  weights = NULL,
  include_top = TRUE,
  classes = 11,
  input_shape = c(224, 224, 3)
)

model <- conv_base

Piąta sieć

Architektura ta okazała się być najlepsza ze wszystkich dotychczasowych, osiągając blisko 60% na zbiorze walidacyjnym.

Szósty projekt sieci

W tym podejściu postanowiliśmy zastosować predefiniowaną sieć NASNetMobile, ze względu na jej niewielki rozmiar oraz fakt, że jak na razie gotowe architektury, uczone od początku (losowo inicjalizowane wagi), dawały najlepsze wyniki.

conv_base <- application_nasnetmobile(
  weights = NULL,
  include_top = TRUE,
  classes = 11,
  input_shape = c(224, 224, 3)
)

model <- conv_base

Szósta siec

Wyniki okazały się być nieco gorsze od poprzedniej architektury oparej na DenseNet121, poniważ jest to około 55% celności na zbiorze walidacyjnym. Dodatkowo w tym przypadku efekt przeuczenia jest mniejszy niż przy poprzedniej architekturze, daje to więc potencjał do poprawy.

Klasyfikacja stylu obrazu

  • 0 - Abstrakcjonizm ekspresyjny;

  • 1 - Malowidło akcji;

  • 2 - Kubizm anlityczny;

  • 3 - Secesja;

  • 4 - Barok;

  • 5 - Malarstwo barwnych płaszczyzn;

  • 6 - Realizm współczesny;

  • 7 - Kubizm;

  • 8 - Wczesny Renesans;

  • 9 - Ekspresjonizm;

  • 10 - Fowizm;

  • 11 - Późny renesans;

  • 12 - Impresjonizm;

  • 13 - Manieryzm późnego renesansu;

  • 14 - Minimalizm;

  • 15 - Prymitywizm (Naïve art);

  • 16 - Nowy realizm;

  • 17 - Renesans północny;

  • 18 - Puentylizm;

  • 19 - Pop-art;

  • 20 - Postimpresjonizm;

  • 21 - Realizm;

  • 22 - Rokoko;

  • 23 - Romantyzm;

  • 24 - Symbolizm;

  • 25 - Kubizm syntetyczny;

  • 26 - Ukiyo-e;

  • 27 - Styl nieznany.

Pierwszy projekt sieci

Pierwszą architekturę sieci do rozpoznawania styli malarstwa postanowiliśmy oprzeć o wcześniej wyuczoną sieć ResNet50 z odmrożonymi dwoma blokami konwolucji.

W tym przypadku zdecydowaliśmy się na mniejszy blok gęsty względem architektury do rozpoznawania gatunków.

Kod
conv_base <- application_resnet50(
  weights = "imagenet",
  include_top = F,
  input_shape = c(224,224,3)
)

model <- keras_model_sequential() %>%
  conv_base %>%
  layer_flatten() %>%
  layer_dense(units = 256, activation = "relu") %>%
  layer_dense(units = 27, activation = "softmax")
Model: "sequential_4"
_____________________________________________________________________
Layer (type)                   Output Shape               Param #    
=====================================================================
resnet50 (Functional)          (None, 7, 7, 2048)         23587712   
_____________________________________________________________________
flatten_4 (Flatten)            (None, 100352)             0          
_____________________________________________________________________
dense_10 (Dense)               (None, 256)                25690368   
_____________________________________________________________________
dense_9 (Dense)                (None, 27)                 6939       
=====================================================================
Total params: 49,285,019
Trainable params: 49,231,899
Non-trainable params: 53,120
_____________________________________________________________________

Podczas uczenia callbacki ustawione były na:

  • Zapisywanie modelu po każdej epoce;

  • Przerwanie procesu uczenia, jeżeli funkcja straty nie poprawi się na zbiorze walidacyjnym po 8 epokach;

  • Obniżenie learning rate, jeżeli funkcja straty nie poprawi się na zbiorze walidacyjnym po 4 epokach.

Niestety, proces uczenia został przerwany ze względu na limity platformy kaggle (kompilacja notatnika osiągnęła 12h), z tego względu dysponujemy jedynie logami dla rezultatów 27 epoki:

loss: 2.1323;

acc: 0.3101;

val_loss: 2.2895;

val_acc: 0.2795;

lr: 1.0000e-06.

Drugi projekt sieci

Jako następną architekturę sieci postanowliśmy skorzystać z używanej już wcześniej architektury, która została wykorzystana jako czwarta w zadniu klasyfikacji gatunków (Section 2.4), do czego skłoniły nas osiągane przez nią wyniki.

Kod
model <- keras_model_sequential() %>%
  layer_conv_2d(filters = 128, kernel_size = c(3, 3),
                input_shape = c(224, 224, 3)) %>%
  layer_activation_leaky_relu(alpha = 0.1) %>% 
  layer_max_pooling_2d(pool_size = c(2, 2)) %>%
  layer_conv_2d(filters = 128, kernel_size = c(3, 3)) %>%
  layer_activation_leaky_relu(alpha = 0.1) %>% 
  layer_max_pooling_2d(pool_size = c(2, 2)) %>%
  layer_dropout(rate = 0.2) %>% 
  layer_conv_2d(filters = 64, kernel_size = c(3, 3)) %>%
  layer_activation_leaky_relu(alpha = 0.1) %>% 
  layer_max_pooling_2d(pool_size = c(2, 2)) %>%
  layer_dropout(rate = 0.3) %>% 
  layer_conv_2d(filters = 32, kernel_size = c(3, 3)) %>%
  layer_activation_leaky_relu(alpha = 0.1) %>% 
  layer_max_pooling_2d(pool_size = c(2, 2)) %>%
  layer_flatten() %>%
  layer_dropout(rate = 0.5) %>% 
  layer_dense(units = 512, activation = "relu") %>%
  layer_activity_regularization(l2 = 0.001) %>% 
  layer_dense(units = 27, activation = "softmax")
Model: "sequential_5"
________________________________________________________________________________
Layer (type)                        Output Shape                    Param #     
================================================================================
conv2d_17 (Conv2D)                  (None, 222, 222, 128)           3584        
________________________________________________________________________________
leaky_re_lu_7 (LeakyReLU)           (None, 222, 222, 128)           0           
________________________________________________________________________________
max_pooling2d_14 (MaxPooling2D)     (None, 111, 111, 128)           0           
________________________________________________________________________________
conv2d_16 (Conv2D)                  (None, 109, 109, 128)           147584      
________________________________________________________________________________
leaky_re_lu_6 (LeakyReLU)           (None, 109, 109, 128)           0           
________________________________________________________________________________
max_pooling2d_13 (MaxPooling2D)     (None, 54, 54, 128)             0           
________________________________________________________________________________
dropout_9 (Dropout)                 (None, 54, 54, 128)             0           
________________________________________________________________________________
conv2d_15 (Conv2D)                  (None, 52, 52, 64)              73792       
________________________________________________________________________________
leaky_re_lu_5 (LeakyReLU)           (None, 52, 52, 64)              0           
________________________________________________________________________________
max_pooling2d_12 (MaxPooling2D)     (None, 26, 26, 64)              0           
________________________________________________________________________________
dropout_8 (Dropout)                 (None, 26, 26, 64)              0           
________________________________________________________________________________
conv2d_14 (Conv2D)                  (None, 24, 24, 32)              18464       
________________________________________________________________________________
leaky_re_lu_4 (LeakyReLU)           (None, 24, 24, 32)              0           
________________________________________________________________________________
max_pooling2d_11 (MaxPooling2D)     (None, 12, 12, 32)              0           
________________________________________________________________________________
flatten_5 (Flatten)                 (None, 4608)                    0           
________________________________________________________________________________
dropout_7 (Dropout)                 (None, 4608)                    0           
________________________________________________________________________________
dense_12 (Dense)                    (None, 512)                     2359808     
________________________________________________________________________________
activity_regularization_1 (Activity (None, 512)                     0           
________________________________________________________________________________
dense_11 (Dense)                    (None, 27)                      13851       
================================================================================
Total params: 2,617,083
Trainable params: 2,617,083
Non-trainable params: 0
________________________________________________________________________________

Druga sieć

Pomimo faktu, że i przy tej strukturze sieci następuje przeuczenie, osiąga ona taki sam wynik, na zbiorze uczącym po 3 epokach, co struktura oparta na ResNet50 osiągnęła po 27 epokach.

Trzeci projekt sieci

Wyniki uzyskane przy klasyfikacji gatunków, przez szkoloną od początku architekturę DenseNet121, skłoniły nas do użycia jej w zadaniu klasyfikacji stylów.

conv_base <- application_densenet121(
  weights = NULL,
  include_top = TRUE,
  classes = 11,
  input_shape = c(224, 224, 3)
)

model <- conv_base

Trzecia sieć

Decyzja ta okazała się być trafiona, po raz pierwszy udało się osiągnąć celnośc powyżej 50% (~52%).

Ewaluacja modeli

Gatunki

Gatunki

model

loss

accuracy

top3

top5

Arch1

1.535

0.456

0.783

0.913

Arch2

1.645

0.433

0.773

0.905

ResNet50

1.690

0.425

0.765

0.903

Arch3

1.595

0.483

0.772

0.907

DensNet121

1.240

0.566

0.792

0.917

NASNetMobile

1.262

0.565

0.803

0.922

W przypadku modeli przeznaczonych do klasyfikacji gatunków malarstwa, najlepiej sprawdziły się architektury DenseNet121 i NASNetMobile trenowane od początku. Obie sieci osiągają bardzo zbliżone wyniki z niewielką przewagą na korzyść architektury DenseNet, ze względu na funkcję straty.

Najgorszą architekturą okzał się ResNet50, przetrenowany wcześniej na zbiorze “Imagenet”, z odmrożonymi dwoma blokami konwolucyjnymi. Przypuszczać można, że spowodowane jest to faktem, iż charakter zadania jest bardziej abstrakcyjny niż klasy zawarte w zbiorze uczącym tej architektury.

Warto zauważyć, że pierwsza architektura, będąca zarazem najprostrszą i ucząca się na niewielkim wycinku zbioru uczącego, osiągneła lepsze wyniki, niż struktury bardziej złożone.

Warto w tym przypadku nadmienićm że miara top 5 przy 11 kategoriach nie jest aż tak dobrym odzwierciedleniem jakości klasyfkiacji. Najważniejsze dalej będzie accuracy oraz top 3.

W przypadku miary top 3 dwa ostatnie modele osiągają zadowalające wyniki na poziomie ~80%

Style

Style

model

loss

accuracy

top3

top5

ResNet50

2.295

0.275

0.770

0.892

Arch3

2.189

0.370

0.755

0.880

DensNet121

1.593

0.495

0.758

0.881

W przypadku klasyfikacji styli malarskich, wyniki są bardzo podobne do tych obserwowanych przy gatunkach. Najgorzej wypada wcześniej nauczona sieć ResNet50, osiągając bardzo niskie accuracy 27,5% i o dziwo najwyższe wyniki na miarach top 3 i top 5.

Ze względu na funkcję straty i accuracy, zdecydowanie najlepiej wypadła architektura DenseNet121 osiągając prawie 50% celności.

W tym przypadku metryka top 5 jest znacznie bardziej miarodajna, ze względu na fakt, że tym razem zadanie ma 27 kategorii.

Decydując się na model oparty na DenseNet121, jesteśmy w stanie osiągnać zadowaljący wynik 75% przy metryce top 3.

Predykcja

Camille Corot “large sharecropping farm”

\[ \text{Gatunek: Pejzaż} \qquad \text{Styl: Realizm} \]

Gatunek

Prawdop.

Martwa natura

30.15

Malarstwo rodzajowe

23.14

Szkic

16.23

Pejzaż

8.30

Ilustracja

6.16

Styl

Prawdop.

Minimalizm

34.59

Nowy realizm

34.34

Barok

19.39

Realizm

8.76

Kubizm

2.55

Vincent Van Gogh “view on the singel in amsterdam”

\[ \text{Gatunek: Pejzaż miejski} \qquad \text{Styl: Realizm} \]

Gatunek

Prawdop.

Malarstwo nagie

51.29

Malarstwo rodzajowe

27.10

Ilustracja

8.45

Malarstwo abstrakcyjne

7.64

Malarstwo religijne

1.85

Styl

Prawdop.

Minimalizm

100

Barok

0

Nowy realizm

0

Wczesny Renesans

0

Kubizm

0

Katsushika Hokusai “Tsukada island in the Musashi province”

\[ \text{Gatunek: Gatunek nieznany} \qquad \text{Styl: Ukiyo-e} \]

Gatunek

Prawdop.

Szkic

57.66

Malarstwo rodzajowe

19.14

Ilustracja

18.38

Malarstwo religijne

1.71

Pejzaż

1.24

Styl

Prawdop.

Minimalizm

46.56

Nowy realizm

19.95

Ekspresjonizm

7.91

Ukiyo-e

7.86

Kubizm

5.61

Vasily Perov “sermon in a village”

\[ \text{Gatunek: Malarstwo rodzajowe} \qquad \text{Styl: Realizm} \]

Gatunek

Prawdop.

Malarstwo nagie

97.85

Pejzaż miejski

1.75

Ilustracja

0.28

Malarstwo rodzajowe

0.09

Martwa natura

0.03

Styl

Prawdop.

Pop-art

93.54

Późny renesans

3.74

Ukiyo-e

1.55

Abstrakcjonizm ekspresyjny

0.52

Renesans północny

0.28

Orest Kiprensky “athena”

\[ \text{Gatunek: Szkic} \qquad \text{Styl: Romantyzm} \]

Gatunek

Prawdop.

Pejzaż miejski

80.77

Malarstwo nagie

18.26

Malarstwo rodzajowe

0.76

Ilustracja

0.19

Martwa natura

0.01

Styl

Prawdop.

Minimalizm

93.66

Realizm

3.02

Nowy realizm

1.68

Prymitywizm (Naïve art)

1.37

Renesans północny

0.10

Linki do prac

Budowa modeli: https://www.kaggle.com/code/datachad/projekt-cv.

Ewaluacja modeli: https://www.kaggle.com/code/datachad/projekt-cv-eval.

Repozytorium: https://github.com/Chajf/Projekt_ComputerVision.